<#import "../main.html" as page>
    <@page.main current="/index">
    <style>
        * {
            margin: 0;
            outline: none;
            padding: 0;
        }

        body {
            font-family: 'Lucida Grande', 'Helvetica', 'Arial';
            font-size: 10px;
            overflow: hidden;
        }

        canvas {
            background: #222;
            cursor: default;
            z-index: 1;
        }

        .nope {
            color: #fff;
            text-align: center;
            margin-top: 150px;
        }

        header {
            position: relative;
            text-shadow: 1px 1px 0px rgba(0, 0, 0, 0.5);
            text-transform: uppercase;
            width: 100%;
            z-index: 10;
        }

        #about {
            color: #fff;
            color: rgba(255, 255, 255, 0.5);
            display: block;
            float: right;
            margin: 20px;
            text-align: right;
            width: 50%;
        }

        h1 {
            color: rgba(255, 255, 255, 0.75);
            float: left;
            font-size: 10px;
            font-weight: normal;
            margin: 20px;
        }

        a {
            color: rgba(255, 255, 255, 0.5);
            display: inline-block;
            text-decoration: none;
            transition: 0.5s ease color;
            -moz-transition: 0.5s ease color;
            -o-transition: 0.5s ease color;
            -webkit-transition: 0.5s ease color;
        }

        a:hover {
            color: rgba(255, 255, 255, 0.75);
        }

        ul#options {
            list-style: none;
            margin: 10px 0 0;
            position: relative;
            right: 0;
            z-index: 10;
        }

        ul#options li {
            margin: 5px 0;
            min-width: 200px;
            opacity: 0;
            transition: 0.25s ease-in opacity;
            -moz-transition: 0.25s ease-in opacity;
            -o-transition: 0.25s ease-in opacity;
            -webkit-transition: 0.25s ease-in opacity;
        }

        ul#options li.group {
            margin-top: 15px;
        }

        ul#options li * {
            display: none;
        }

        ul#options li a {
            box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.25);
            background-color: rgba(0, 0, 0, 0.5);
            border-radius: 3px;
            padding: 3px 5px;
            position: relative;
            transition: 0.5s ease all;
            -moz-border-radius: 3px;
            -o-box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.25);
            -moz-box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.25);
            -webkit-box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.25);
            -moz-transition: 0.5s ease all;
            -o-transition: 0.5s ease all;
            -webkit-transition: 0.5s ease all;
        }

        ul#options li a:hover {
            color: rgba(255, 255, 255, 0.75);
        }

        ul#options li a.on {
            background-color: rgba(255, 255, 255, 0.8);
            color: rgba(0, 0, 0, 0.9);
            text-shadow: 0px 0px 0px;
        }

        ul#options li a.on:after {
            content: "\2713 ";
        }

        ul#options.on li {
            opacity: 1;
            right: 20px;
        }

        ul#options.on li * {
            display: inline-block;
        }

        ul#borders {
        }

        ul#borders li {
            position: fixed;
            list-style: none;
            margin: 0;
            background-color: transparent;
            background-color: rgba(0, 0, 0, 0.05);
            z-index: 100;
        }

        li#top {
            height: 10px;
            left: 0;
            right: 0;
            top: 0;
        }

        li#right {
            bottom: 10px;
            right: 0;
            top: 10px;
            width: 10px;
        }

        li#bottom {
            bottom: 0;
            height: 10px;
            left: 0;
            right: 0;
        }

        li#left {
            bottom: 10px;
            left: 0;
            top: 10px;
            width: 10px;
        }
    </style>
    <canvas style="width:100%" height="400" id="canvas"><p class="nope">No canvas, no particles</p></canvas>
    <header>
        <div id="about">
            <a href="#" id="toggle-options"></a>
            <ul id="options">
                <li><a href="#" id="quivers" class="">Quiver</a></li>
                <li><a href="#" id="gradient" class="on">Gradient</a></li>
                <li><a href="#" id="color" class="on">Colorize</a></li>
                <li><a href="#" id="valentineify" class="">Valentine-ify</a></li>
                <li class="group"><span>Mouse down: explode and repel</span></li>
                <li><span>Mouse down + shift: explode and attract</span></li>
                <li><span>Arrow Up: increase particle size</span></li>
                <li class="group"><span>Sorry about your CPU</span></li>
                <li><span id="fps"></span></li>
            </ul>
        </div>
    </header>
    <script type="text/javascript">
        var Clock = (function () {

            // private variables
            var canvas, // canvas element
                ctx, // canvas context
                bgGrad = true, // background gradient flag
                gradient, // gradient (background)
                height = 400, // canvas height
                key = {up: false, shift: false}, // key presses
                particles = [], // particle array
                particleColor = 'hsla(0, 0%, 100%, 0.3)', // particle color
                mouse = {x: 0, y: 0}, // position of mouse / touch
                press = false, // pressed flag
                quiver = false, // quiver flag
                text, // the text to copy pixels from
                textSize = 140, // (initial) textsize
                valentine = false, // valentine-ify it for a bit?
                msgTime = 100, // time to show a message before returning to clock
                updateColor = true, // update color of gradient / particles with time?
                width = 800; // canvas width

            // Constants
            var FRAME_RATE = 20, // frames per second target
                MIN_WIDTH = 800, // minimum width of canvas
                MIN_HEIGHT = 400, // minimum height of canvas
                PARTICLE_NUM = 600, // (max) number of particles to generate
                RADIUS = Math.PI * 2; // radius of particle

            var defaultStyles = function () {
                textSize = 140;
                // particle color
                particleColor = 'hsla(0, 0%, 100%, 0.3)';

                // color stops
                var gradientStops = {
                    0: '#333333',
                    0.5: '#222222'
                };

                // create gradient
                setGradient(gradientStops);
            };

            var draw = function (p) {
                ctx.fillStyle = particleColor;
                ctx.beginPath();
                ctx.arc(p.x, p.y, p.size, 0, RADIUS, true);
                ctx.closePath();
                ctx.fill();
            };

            var explode = function () {
                for (var i = 0, l = particles.length; i < l; i++) {
                    var p = particles[i];

                    if (p.inText) {

                        var ax = mouse.x - p.px,
                            ay = mouse.y - p.py,
                            angle = Math.atan2(ay, ax),
                            polarity,
                            C = Math.cos(angle),
                            S = Math.sin(angle);

                        // change polarity
                        // attract particles if mouse pressed, repel if shift + mousedown
                        polarity = (key.shift === true) ? -1 : 1;

                        p.x += polarity * (Math.pow((C - 1), 2) - 1) + p.velocityX * p.delta;
                        p.y += polarity * (Math.pow((S - 1), 2) - 1) + p.velocityY * p.delta;

                        // set previous positions
                        p.px = p.x;
                        p.py = p.y;

                        draw(p);
                    }
                }
            };

            var getTime = function (amPM) {
                var date = new Date(),
                    hours = date.getHours(),
                    timeOfDay = '';

                if (amPM) {
                    hours = (hours > 12) ? hours -= 12 : hours;
                    hours = (hours == 0) ? 12 : hours;
                } else {
                    hours = pad(hours);
                }

                var minutes = pad(date.getMinutes());
                var seconds = pad(date.getSeconds());
                return {
                    hours: hours,
                    minutes: minutes,
                    seconds: seconds,
                    timeString: hours + " : " + minutes + " : " + seconds
                };
            };

            // animation loop
            var loop = function () {

                // clear out text
                ctx.clearRect(0, 0, width, height);

                var time = getTime(true);

                textSize = 140;

                // draw text on canvas
                if (valentine === true) {
                    if (msgTime > 0) {
                        textSize = 180;
                        text = '?';
                        msgTime--;
                    } else {
                        text = time.timeString;
                    }
                    // valentine-ify it by setting hue to pink
                    setStyles(300);

                } else if (updateColor === true && bgGrad === true) {
                    // changing color with time
                    var color = time.hours + time.minutes + time.seconds;
                    setStyles(color);
                    text = time.timeString;
                } else {
                    defaultStyles();
                    text = time.timeString;
                }

                ctx.fillStyle = "rgb(255, 255, 255)";
                ctx.textBaseline = "middle";
                ctx.font = textSize + "px 'Avenir', 'Helvetica Neue', 'Arial', 'sans-serif'";
                ctx.fillText(text, (width - ctx.measureText(text).width) * 0.5, height * 0.4); // 修改位置

                // copy pixels
                var imgData = ctx.getImageData(0, 0, width, height);

                // clear canvas, again
                ctx.clearRect(0, 0, width, height);

                if (bgGrad === true) {
                    // draw gradient
                    ctx.fillStyle = gradient;
                    ctx.fillRect(0, 0, width, height);
                }

                if (press === false) {
                    // reset particles
                    for (var i = 0, l = particles.length; i < l; i++) {
                        var p = particles[i];
                        p.inText = false;
                    }
                    particleText(imgData);
                } else {
                    explode();
                }
                FPS.update('fps');
            };

            var pad = function (number) {
                return ('0' + number).substr(-2);
            };

            var particleText = function (imgData) {

                var pxls = [];
                for (var w = width; w > 0; w -= 6) {
                    for (var h = 0; h < width; h += 6) {
                        var index = (w + h * (width)) * 4;
                        if (imgData.data[index] > 10) {
                            pxls.push([w, h]);
                        }
                    }
                }

                var count = pxls.length;
                for (var i = 0; i < pxls.length && i < particles.length; i++) {
                    try {
                        var p = particles[i],
                            X,
                            Y;

                        if (quiver) {
                            X = (pxls[count - 1][0]) - (p.px + Math.random() * 5);
                            Y = (pxls[count - 1][1]) - (p.py + Math.random() * 5);
                        } else {
                            X = (pxls[count - 1][0]) - p.px;
                            Y = (pxls[count - 1][1]) - p.py;
                        }

                        // tangent
                        var T = Math.sqrt(X * X + Y * Y);

                        // arctangent
                        var A = Math.atan2(Y, X);

                        // cosine
                        var C = Math.cos(A);

                        // sine
                        var S = Math.sin(A);

                        // set new postition
                        p.x = p.px + C * T * p.delta;
                        p.y = p.py + S * T * p.delta;

                        // set previous positions
                        p.px = p.x;
                        p.py = p.y;

                        p.inText = true;

                        // draw the particle
                        draw(p);

                        if (key.up === true) {
                            p.size += 0.3;
                        } else {
                            var newSize = p.size - 0.5;
                            if (newSize > p.origSize && newSize > 0) {
                                p.size = newSize;
                            } else {
                                p.size = m.origSize;
                            }
                        }
                    } catch (e) {
                        //console.log(e);
                    }
                    count--;
                }
            };

            var setCoordinates = function (e) {
                if (e.offsetX) {
                    return {x: e.offsetX, y: e.offsetY}; // use offset if available
                } else if (e.layerX) {
                    return {x: e.layerX, y: e.layerY}; // firefox... make sure to position the canvas
                } else {
                    // iOS. Maybe others too?
                    return {x: e.pageX - canvas.offsetLeft, y: e.pageY - canvas.offsetTop};
                }
            };

            // set dimensions of canvas
            var setDimensions = function () {
                width = Math.max(window.innerWidth, MIN_WIDTH);
                height = Math.max(window.innerHeight, MIN_HEIGHT);

                // Resize the canvas
                canvas.width = width;
                canvas.height = height;

                canvas.style.position = 'relative';
                canvas.style.left = '0px';
                canvas.style.top = '0px';
            };

            var setGradient = function (gradientStops) {

                // create gradient
                gradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, width);

                // iterate through colorstops
                for (var position in gradientStops) {
                    //var color = gradientStops[position];
                    var color = "#fff"; //修改背景颜色
                    gradient.addColorStop(position, color);
                }
            };

            var setStyles = function (hue) {
                // color stops
                var gradientStops = {
                    0: 'hsl(' + hue + ', 100%, 100%)',
                    0.5: 'hsl(' + hue + ', 10%, 50%)'
                };

                // change particle color
                particleColor = 'hsla(' + hue + ', 10%, 50%, 0.3)';

                // create gradient
                setGradient(gradientStops);
            };

            /**
             * Public Methods
             */
            return {

                init: function (canvasID) {

                    canvas = document.getElementById(canvasID);
                    // make sure canvas exists and that the browser understands it
                    if (canvas === null || !canvas.getContext) {
                        return;
                    }
                    // set context
                    ctx = canvas.getContext("2d");

                    // set dimensions
                    setDimensions();

                    // ui
                    this.ui();

                    for (var i = 0; i < PARTICLE_NUM; i++) {
                        particles[i] = new Particle(canvas);
                    }

                    // show FPS
                    FPS.initialize(canvas, 'fps');

                    // set defaults
                    defaultStyles();

                    // let's do this
                    setInterval(loop, FRAME_RATE);

                },

                ui: function () {

                    // UI: buttons and events
                    var toggleOptions = document.getElementById('toggle-options'),
                        options = document.getElementById('options'),
                        onMsg = '[-] Hide Options',
                        offMsg = '[+] Show Options',
                        quiverBtn = document.getElementById('quivers'),
                        gradientBtn = document.getElementById('gradient'),
                        valentineifyBtn = document.getElementById('valentineify'),
                        colorBtn = document.getElementById('color');

                    //toggleOptions.innerHTML = offMsg;

                    /**
                     * Events
                     */
                    toggleOptions.addEventListener('click', function (e) {
                        e.preventDefault();
                        if (options.className === 'on') {
                            options.className = '';
                            toggleOptions.innerHTML = offMsg;
                        } else {
                            options.className = 'on';
                            toggleOptions.innerHTML = onMsg;
                        }
                    }, false);

                    quiverBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        if (quiverBtn.className === 'on') {
                            quiverBtn.className = '';
                            quiver = false;
                        } else {
                            quiverBtn.className = 'on';
                            quiver = true;
                        }
                    }, false);

                    gradientBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        if (gradientBtn.className === 'on') {
                            gradientBtn.className = '';
                            bgGrad = false;
                        } else {
                            gradientBtn.className = 'on';
                            bgGrad = true;
                        }
                    }, false);

                    valentineifyBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        if (valentineifyBtn.className === 'on') {
                            valentineifyBtn.className = '';
                            valentine = false;
                            msgTime = 0;
                        } else {
                            valentineifyBtn.className = 'on';
                            msgTime = 60;
                            valentine = true;
                        }
                    }, false);

                    colorBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        if (colorBtn.className === 'on') {
                            colorBtn.className = '';
                            updateColor = false;
                        } else {
                            colorBtn.className = 'on';
                            updateColor = true;
                        }
                    }, false);

                    document.addEventListener('keydown', function (e) {
                        switch (e.keyCode) {
                            case 16: // shift
                                key.shift = true;
                                e.preventDefault();
                                break;
                            case 38: // up key
                                key.up = true;
                                e.preventDefault();
                                break;
                        }
                    }, false);

                    document.addEventListener('keyup', function (e) {
                        switch (e.keyCode) {
                            case 16: // shift
                                key.shift = false;
                                e.preventDefault();
                                break;
                            case 38: // space
                                key.up = false;
                                e.preventDefault();
                                break;
                        }
                    }, false);

                    window.addEventListener('resize', function (e) {
                        setDimensions();
                    }, false);

                    canvas.addEventListener('mousedown', function (e) {
                        press = true;
                    }, false);

                    document.addEventListener('mouseup', function (e) {
                        press = false;
                    }, false);

                    canvas.addEventListener('mousemove', function (e) {
                        if (press) {
                            mouse = setCoordinates(e);
                        }
                    }, false);


                }

            };

        })();

        // Create new particles
        var Particle = function (canvas) {

            var range = Math.random() * 180 / Math.PI, // random starting point
                spread = canvas.height, // how far away from text should the particles begin?
                size = Math.random() * 7; // random size of particle

            this.delta = 0.25;
            this.x = 0;
            this.y = 0;

            // starting positions
            this.px = (canvas.width / 2) + (Math.cos(range) * spread);
            this.py = (canvas.height / 2) + (Math.sin(range) * spread);

            this.velocityX = Math.floor(Math.random() * 10) - 5;
            this.velocityY = Math.floor(Math.random() * 10) - 5;

            this.size = size;
            this.origSize = size;

            this.inText = false;

        };

        var FPS = {

            // defaults
            delta: 0,
            lastTime: 0,
            frames: 0,
            totalTime: 0,
            updateTime: 0,
            updateFrames: 0,

            initialize: function (canvasID, fpsID) {
                this.lastTime = (new Date()).getTime();
                if (!document.getElementById(fpsID) && document.getElementById(canvasID)) {
                    this.createFPS(canvasID, fpsID);
                }
            },

            // create FPS div if needed
            createFPS: function (canvasID, fpsID) {
                var div = document.createElement('div');
                div.setAttribute('id', fpsID);
                var canvas = document.getElementById(canvasID);
                var parent = canvas.parentNode;
                div.innerHTML = "FPS AVG: 0 CURRENT: 0";
                parent.appendChild(div);
            },

            // update FPS count
            update: function (fpsID) {
                var now = (new Date()).getTime();
                this.delta = now - this.lastTime;
                this.lastTime = now;
                this.updateTime += this.delta;
                this.totalTime += this.delta;
                this.frames++;
                this.updateFrames++;
                document.getElementById(fpsID).innerHTML = "FPS Average: " + Math.round(1000 * this.frames / this.totalTime) + " Current: " + Math.round(1000 * this.updateFrames / this.updateTime);
                this.updateTime = 0; // reset time
                this.updateFrames = 0; // reset frames
            }

        };

        Clock.init('canvas');
    </script>
</@page.main>